package com.pingsky.apm.agent.api.util;

import com.pingsky.apm.agent.api.exception.PingSkyException;
import com.pingsky.apm.agent.api.log.BootLogger;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class JarUtil {

    private static BootLogger LOGGER = BootLogger.getLogger(JarUtil.class.getName());

    public static String getJarLocation(String className) {
        final String internalClassName = className.replace('.', '/') + ".class";
        final URL classURL = ClassLoader.getSystemResource(internalClassName);
        if (classURL == null) {
            return null;
        }

        if (classURL.getProtocol().equals("jar")) {
            String path = classURL.getPath();
            int jarIndex = path.indexOf("!/");
            if (jarIndex == -1) {
                throw new IllegalArgumentException("!/ not found " + path);
            }
            final String agentPath = path.substring("file:".length(), jarIndex);
            return agentPath;
        }
        throw new PingSkyException(String.format("no such class:%s in bootstrap class loader", className));
    }

    public static List<URL> resolveLib(File libDir, String[] fileExtensions) {
        if (checkDirectory(libDir)) {
            return Collections.emptyList();
        }
        final File[] libFileList = listFiles(libDir, fileExtensions);

        List<URL> libURLList = toURLs(libFileList);
        // add directory
        URL agentDirUri = toURL(libDir);

        List<URL> jarURLList = new ArrayList<URL>(libURLList);
        jarURLList.add(agentDirUri);
        return jarURLList;
    }

    private static boolean checkDirectory(File file) {
        if (!file.exists()) {
            LOGGER.warn(file + " not found");
            return true;
        }
        if (!file.isDirectory()) {
            LOGGER.warn(file + " is not a directory");
            return true;
        }
        return false;
    }

    private static File[] listFiles(File libDir, String[] p) {
        return FileUtil.listFiles(libDir, p);
    }

    private static URL toURL(File file) {
        try {
            return file.toURI().toURL();
        } catch (IOException e) {
            throw new RuntimeException(file.getName() + ".toURL() failed.", e);
        }
    }

    public static List<URL> toURLs(final File[] files) {
        Assert.requireNonNull(files, "files");
        final URL[] urls = new URL[files.length];
        for (int i = 0; i < files.length; i++) {
            urls[i] = toURL(files[i]);
        }
        return Arrays.asList(urls);
    }
}
